package persistence

import (
	"context"
	"fmt"
	"strings"

	"baseService/internal/domain/repositories"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

// BaseRepositoryImpl 基础仓储实现
// 利用GORM内置的软删除功能，无需手动处理软删除逻辑
// 统一使用uint主键
type BaseRepositoryImpl[T any] struct {
	db *gorm.DB
}

var _ interface {
	repositories.BaseRepository[struct{}]
	repositories.Paginator[struct{}]
	repositories.BatchOperator[struct{}]
	repositories.SoftDeleteRestorer[struct{}]
	repositories.Counter[struct{}]
} = (*BaseRepositoryImpl[struct{}])(nil)

// defaultBatchSize 定义批量创建的默认单批数量，可按需配置覆盖
const defaultBatchSize = 100

// applyQueryOptions 根据 QueryOptions 构建通用查询（字段、预加载、过滤、排序）
func applyQueryOptions(db *gorm.DB, options *repositories.QueryOptions) *gorm.DB {
	if options == nil {
		return db
	}

	if len(options.Fields) > 0 {
		db = db.Select(options.Fields)
	}

	for _, preload := range options.Preload {
		if preload != "" {
			db = db.Preload(preload)
		}
	}

	for field, value := range options.Filters {
		if field == "" {
			continue
		}
		db = db.Where(map[string]interface{}{field: value})
	}

	for _, condition := range options.Conditions {
		if condition.Field == "" {
			continue
		}

		op := strings.ToLower(condition.Operator)
		switch op {
		case "like":
			if v, ok := condition.Value.(string); ok {
				db = db.Where(condition.Field+" LIKE ?", "%"+v+"%")
			}
		case "prefix_like":
			if v, ok := condition.Value.(string); ok {
				db = db.Where(condition.Field+" LIKE ?", v+"%")
			}
		case "suffix_like":
			if v, ok := condition.Value.(string); ok {
				db = db.Where(condition.Field+" LIKE ?", "%"+v)
			}
		case "gt", ">":
			db = db.Where(condition.Field+" > ?", condition.Value)
		case "gte", ">=":
			db = db.Where(condition.Field+" >= ?", condition.Value)
		case "lt", "<":
			db = db.Where(condition.Field+" < ?", condition.Value)
		case "lte", "<=":
			db = db.Where(condition.Field+" <= ?", condition.Value)
		case "between":
			db = db.Where(condition.Field+" BETWEEN ? AND ?", condition.Value, condition.Value2)
		case "in":
			db = db.Where(condition.Field+" IN ?", condition.Value)
		default:
			db = db.Where(condition.Field+" = ?", condition.Value)
		}
	}

	if options.OrderBy != "" {
		db = db.Order(clause.OrderByColumn{
			Column: clause.Column{Name: options.OrderBy},
			Desc:   strings.EqualFold(options.Order, "desc"),
		})
	}

	return db
}

// baseQuery 基于上下文和选项返回绑定模型的基础查询
func (r *BaseRepositoryImpl[T]) baseQuery(ctx context.Context, options *repositories.QueryOptions) *gorm.DB {
	return applyQueryOptions(r.db.WithContext(ctx).Model(new(T)), options)
}

// NewBaseRepository 创建基础仓储实现
func NewBaseRepository[T any](db *gorm.DB) repositories.BaseRepository[T] {
	return &BaseRepositoryImpl[T]{
		db: db,
	}
}

// Create 创建实体
func (r *BaseRepositoryImpl[T]) Create(ctx context.Context, entity *T) error {
	if err := r.db.WithContext(ctx).Create(entity).Error; err != nil {
		return fmt.Errorf("create entity failed: %w", err)
	}
	return nil
}

// Update 更新指定字段
func (r *BaseRepositoryImpl[T]) Update(ctx context.Context, id uint, fields map[string]interface{}) error {
	if len(fields) == 0 {
		return nil
	}
	if err := r.db.WithContext(ctx).Model(new(T)).Where("id = ?", id).Updates(fields).Error; err != nil {
		return fmt.Errorf("update entity %d failed: %w", id, err)
	}
	return nil
}

// Delete 删除实体（软删除 - GORM自动处理）
// 对于有gorm.DeletedAt字段的实体，GORM会自动进行软删除
// 对于没有gorm.DeletedAt字段的实体，GORM会进行物理删除
func (r *BaseRepositoryImpl[T]) Delete(ctx context.Context, id uint) error {
	var entity T
	if err := r.db.WithContext(ctx).Where("id = ?", id).Delete(&entity).Error; err != nil {
		return fmt.Errorf("delete entity %d failed: %w", id, err)
	}
	return nil
}

// ForceDelete 物理删除实体
// 即使实体有gorm.DeletedAt字段，也会强制进行物理删除
func (r *BaseRepositoryImpl[T]) ForceDelete(ctx context.Context, id uint) error {
	var entity T
	if err := r.db.WithContext(ctx).Unscoped().Where("id = ?", id).Delete(&entity).Error; err != nil {
		return fmt.Errorf("force delete entity %d failed: %w", id, err)
	}
	return nil
}

// GetByID 根据ID获取实体
// GORM会自动过滤掉软删除的记录
func (r *BaseRepositoryImpl[T]) GetByID(ctx context.Context, id uint) (*T, error) {
	var entity T
	err := r.db.WithContext(ctx).Where("id = ?", id).First(&entity).Error
	if err != nil {
		return nil, err
	}
	return &entity, nil
}

// GetAll 获取所有实体
// GORM会自动过滤掉软删除的记录
func (r *BaseRepositoryImpl[T]) GetAll(ctx context.Context) ([]*T, error) {
	var entities []*T
	err := r.db.WithContext(ctx).Find(&entities).Error
	return entities, err
}

// GetWithPagination 分页查询（传统方式，适合需要总数的场景）
func (r *BaseRepositoryImpl[T]) GetWithPagination(ctx context.Context, page, pageSize int, options *repositories.QueryOptions) ([]*T, int64, error) {
	var entities []*T
	var total int64

	if options == nil {
		options = &repositories.QueryOptions{}
	}
	options.Normalize(page, pageSize, 500)
	page = options.Page
	pageSize = options.PageSize

	baseQuery := r.baseQuery(ctx, options)
	countQuery := baseQuery.Session(&gorm.Session{NewDB: true})

	if err := countQuery.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("count entities failed: %w", err)
	}

	// 计算偏移量
	offset := (page - 1) * pageSize

	dataQuery := baseQuery.Session(&gorm.Session{NewDB: true})
	if err := dataQuery.Offset(offset).Limit(pageSize).Find(&entities).Error; err != nil {
		return nil, 0, fmt.Errorf("list entities failed: %w", err)
	}
	return entities, total, nil
}

// GetByCondition 根据条件查询
func (r *BaseRepositoryImpl[T]) GetByCondition(ctx context.Context, options *repositories.QueryOptions) ([]*T, error) {
	var entities []*T
	query := r.baseQuery(ctx, options)

	if err := query.Find(&entities).Error; err != nil {
		return nil, fmt.Errorf("get entities by condition failed: %w", err)
	}
	return entities, nil
}

// GetOneByCondition 根据条件查询单个实体
func (r *BaseRepositoryImpl[T]) GetOneByCondition(ctx context.Context, options *repositories.QueryOptions) (*T, error) {
	var entity T
	query := r.baseQuery(ctx, options)

	if err := query.First(&entity).Error; err != nil {
		return nil, fmt.Errorf("get entity by condition failed: %w", err)
	}
	return &entity, nil
}

// CreateBatch 按默认批量大小创建多条记录
func (r *BaseRepositoryImpl[T]) CreateBatch(ctx context.Context, entities []*T) error {
	if len(entities) == 0 {
		return nil
	}
	if err := r.db.WithContext(ctx).CreateInBatches(entities, defaultBatchSize).Error; err != nil {
		return fmt.Errorf("batch create entities failed: %w", err)
	}
	return nil
}

// UpdateBatch 批量更新（逐条字段更新）
func (r *BaseRepositoryImpl[T]) UpdateBatch(ctx context.Context, items map[uint]map[string]interface{}) error {
	if len(items) == 0 {
		return nil
	}

	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		for id, fields := range items {
			if len(fields) == 0 {
				continue
			}
			if err := tx.Model(new(T)).Where("id = ?", id).Updates(fields).Error; err != nil {
				return fmt.Errorf("update entity %d failed: %w", id, err)
			}
		}
		return nil
	})
}

// UpdateFieldsBatch 批量更新指定字段
func (r *BaseRepositoryImpl[T]) UpdateFieldsBatch(ctx context.Context, ids []uint, fields map[string]interface{}) error {
	if len(ids) == 0 {
		return nil
	}

	if err := r.db.WithContext(ctx).Model(new(T)).Where("id IN ?", ids).Updates(fields).Error; err != nil {
		return fmt.Errorf("batch update entities %v failed: %w", ids, err)
	}
	return nil
}

// DeleteBatch 批量软删除
func (r *BaseRepositoryImpl[T]) DeleteBatch(ctx context.Context, ids []uint) error {
	if len(ids) == 0 {
		return nil
	}

	var entity T
	if err := r.db.WithContext(ctx).Where("id IN ?", ids).Delete(&entity).Error; err != nil {
		return fmt.Errorf("delete entities %v failed: %w", ids, err)
	}
	return nil
}

// ForceDeleteBatch 批量物理删除
func (r *BaseRepositoryImpl[T]) ForceDeleteBatch(ctx context.Context, ids []uint) error {
	if len(ids) == 0 {
		return nil
	}

	var entity T
	if err := r.db.WithContext(ctx).Unscoped().Where("id IN ?", ids).Delete(&entity).Error; err != nil {
		return fmt.Errorf("force delete entities %v failed: %w", ids, err)
	}
	return nil
}

// Count 计数
func (r *BaseRepositoryImpl[T]) Count(ctx context.Context, options *repositories.QueryOptions) (int64, error) {
	var count int64
	query := r.baseQuery(ctx, options)

	if err := query.Count(&count).Error; err != nil {
		return 0, fmt.Errorf("count entities failed: %w", err)
	}
	return count, nil
}

// Exists 检查是否存在
func (r *BaseRepositoryImpl[T]) Exists(ctx context.Context, options *repositories.QueryOptions) (bool, error) {
	count, err := r.Count(ctx, options)
	return count > 0, err
}

// ExistsById 根据ID检查是否存在
func (r *BaseRepositoryImpl[T]) ExistsById(ctx context.Context, id uint) (bool, error) {
	var count int64
	if err := r.db.WithContext(ctx).Model(new(T)).Where("id = ?", id).Count(&count).Error; err != nil {
		return false, fmt.Errorf("count entity %d failed: %w", id, err)
	}
	return count > 0, nil
}

// GetWithDeleted 获取包含软删除的所有数据
func (r *BaseRepositoryImpl[T]) GetWithDeleted(ctx context.Context) ([]*T, error) {
	var entities []*T
	err := r.db.WithContext(ctx).Unscoped().Find(&entities).Error
	return entities, err
}

// GetDeletedOnly 只获取软删除的数据
func (r *BaseRepositoryImpl[T]) GetDeletedOnly(ctx context.Context) ([]*T, error) {
	var entities []*T
	err := r.db.WithContext(ctx).Unscoped().Where("deleted_at IS NOT NULL").Find(&entities).Error
	return entities, err
}

// Restore 恢复软删除的数据
func (r *BaseRepositoryImpl[T]) Restore(ctx context.Context, id uint) error {
	return r.db.WithContext(ctx).Unscoped().Model(new(T)).Where("id = ?", id).Update("deleted_at", nil).Error
}

// RestoreBatch 批量恢复软删除的数据
func (r *BaseRepositoryImpl[T]) RestoreBatch(ctx context.Context, ids []uint) error {
	if len(ids) == 0 {
		return nil
	}
	return r.db.WithContext(ctx).Unscoped().Model(new(T)).Where("id IN ?", ids).Update("deleted_at", nil).Error
}

// WithTx 使用事务
func (r *BaseRepositoryImpl[T]) WithTx(tx interface{}) repositories.BaseRepository[T] {
	gormTx, ok := tx.(*gorm.DB)
	if !ok {
		return r
	}

	return &BaseRepositoryImpl[T]{
		db: gormTx,
	}
}
